﻿using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.RelyingParty;
using DotNetOpenAuth.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Configuration;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using System.Web.Routing;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;

namespace Jizsoft.JFrame.Modeling.Web.Mvc
{
    public class AccountController : Controller
    {
        private static OpenIdRelyingParty openid = new OpenIdRelyingParty();

        public ActionResult Index()
        {
            if (!User.Identity.IsAuthenticated)
            {
                Response.Redirect("~/Account/Login?ReturnUrl=Index");
            }

            return View("Index");
        }

        public ActionResult Login()
        {
            // Stage 1: display login form to user
            return View("Login");
        }

        public ActionResult Authenticate(string returnUrl)
        {
            var response = openid.GetResponse();
            if (response == null)
            {
                // Stage 2: user submitting Identifier
                Identifier id;
                if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
                {
                    try
                    {
                        string returnToUrl = returnUrl;
                        if(string.IsNullOrEmpty(returnUrl))
                        {
                            returnToUrl = "http://localhost:3619/";
                        }
                        var request = openid.CreateRequest(Request.Form["openid_identifier"]);//, new Realm("http://localhost:3619/"), new Uri(returnToUrl));
                        var extension = new FetchRequest();
                        extension.Attributes.Add(new AttributeRequest("email", true));
                        extension.Attributes.Add(new AttributeRequest("nickname", true));
                        extension.Attributes.Add(new AttributeRequest("avatar", true));
                        request.AddExtension(extension);
                        return request.RedirectingResponse.AsActionResultMvc5();
                    }
                    catch (ProtocolException ex)
                    {
                        ViewData["Message"] = ex.Message;
                        return View("Login");
                    }
                }
                else
                {
                    ViewData["Message"] = "Invalid identifier";
                    return View("Login");
                }
            }
            else
            {
                // Stage 3: OpenID Provider sending assertion response
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        {
                            var claims = response.GetExtension<DotNetOpenAuth.OpenId.Extensions.SimpleRegistration.ClaimsRequest>();
                            Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
                            FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
                            if (!string.IsNullOrEmpty(returnUrl))
                            {
                                return Redirect(returnUrl);
                            }
                            else
                            {
                                return RedirectToAction("Index", "Home");
                            }
                        }
                    case AuthenticationStatus.Canceled:
                        ViewData["Message"] = "Canceled at provider";
                        return View("Login");
                    case AuthenticationStatus.Failed:
                        ViewData["Message"] = response.Exception.Message;
                        return View("Login");
                }
            }
            return new EmptyResult();
        }

        //public ActionResult Login(string id)
        //{
        //    return View();
        //}

        //public ActionResult LoginByOpenId(string id)
        //{
        //    OpenIdRelyingParty relyingParty = new OpenIdRelyingParty();
        //    var response = relyingParty.GetResponse();
        //    if(response== null)
        //    {
        //        return ToProvider(relyingParty);
        //    }
        //    else
        //    {
        //        if(response.Status == AuthenticationStatus.Authenticated)
        //        {
        //            FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, true);
        //            if (!string.IsNullOrEmpty(returnUrl))
        //            {
        //                return Redirect(returnUrl);
        //            }
        //            else
        //            {
        //                return RedirectToAction("Index", "Home");
        //            }
        //        }
        //        else
        //        {
        //            return View("Login");
        //        }
        //    }
        //}

        //private ActionResult ToProvider(OpenIdRelyingParty relyingParty)
        //{
        //    return relyingParty.CreateRequest("http://localhost:3636/OpenId/User/jaeho").RedirectingResponse.AsActionResultMvc5();
        //}
        private const string RolesAttribute = "http://samples.dotnetopenauth.net/sso/roles";

        private static OpenIdRelyingParty relyingParty = new OpenIdRelyingParty();

        public ActionResult Login3()
        {
            if (Array.IndexOf(Request.AcceptTypes, "application/xrds+xml") >= 0)
            {
                return View("Xrds");
            }

            UriBuilder returnToBuilder = new UriBuilder(Request.Url);
            returnToBuilder.Path = "/Account/Login";
            returnToBuilder.Query = null;
            returnToBuilder.Fragment = null;
            Uri returnTo = returnToBuilder.Uri;
            returnToBuilder.Path = "/Account/Login";
            Realm realm = returnToBuilder.Uri;

            var response = relyingParty.GetResponse();
            if (response == null)
            {
                if (Request.QueryString["ReturnUrl"] != null && User.Identity.IsAuthenticated)
                {
                    // The user must have been directed here because he has insufficient
                    // permissions to access something.
                    this.ViewBag.Message = "1";
                }
                else
                {
                    // Because this is a sample of a controlled SSO environment,
                    // we don't ask the user which Provider to use... we just send
                    // them straight off to the one Provider we trust.
                    var request = relyingParty.CreateRequest(
                        ConfigurationManager.AppSettings["SsoProviderOPIdentifier"],
                        realm,
                        returnTo);
                    var fetchRequest = new FetchRequest();
                    fetchRequest.Attributes.AddOptional(RolesAttribute);
                    request.AddExtension(fetchRequest);
                    request.RedirectToProvider();
                }
            }
            else
            {
                switch (response.Status)
                {
                    case AuthenticationStatus.Canceled:
                        this.ViewBag.Message = "Login canceled.";
                        break;
                    case AuthenticationStatus.Failed:
                        this.ViewBag.Message = HttpUtility.HtmlEncode(response.Exception.Message);
                        break;
                    case AuthenticationStatus.Authenticated:
                        IList<string> roles = null;
                        var fetchResponse = response.GetExtension<FetchResponse>();
                        if (fetchResponse != null)
                        {
                            if (fetchResponse.Attributes.Contains(RolesAttribute))
                            {
                                roles = fetchResponse.Attributes[RolesAttribute].Values;
                            }
                        }
                        if (roles == null)
                        {
                            roles = new List<string>(0);
                        }

                        // Apply the roles to this auth ticket
                        const int TimeoutInMinutes = 100; // TODO: look up the right value from the web.config file
                        var ticket = new FormsAuthenticationTicket(
                            2,
                            response.ClaimedIdentifier,
                            DateTime.Now,
                            DateTime.Now.AddMinutes(TimeoutInMinutes),
                            false, // non-persistent, since login is automatic and we wanted updated roles
                            string.Join(";", roles.ToArray()));

                        HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
                        Response.SetCookie(cookie);
                        Response.Redirect(Request.QueryString["ReturnUrl"] ?? FormsAuthentication.DefaultUrl);
                        break;
                    default:
                        break;
                }
            }

            return RedirectToAction("Index", "Home");
        }

        public IFormsAuthenticationService FormsService { get; set; }

        protected override void Initialize(RequestContext requestContext)
        {
            if (FormsService == null) { FormsService = new FormsAuthenticationService(); }

            base.Initialize(requestContext);
        }

        public ActionResult LogOff()
        {
            FormsService.SignOut();

            return RedirectToAction("Index", "Home");
        }
    }


    public interface IFormsAuthenticationService
    {
        void SignIn(string userName, bool createPersistentCookie);
        void SignOut();
    }

    public class FormsAuthenticationService : IFormsAuthenticationService
    {
        public void SignIn(string userName, bool createPersistentCookie)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");

            FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
        }

        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }
    }
}